/**
 **************************************************************************************************************************
 * RTTI Implementation:
 * Only usage is: in class definition: add DECLARE_RTTI(CLASS,BASE) with CLASS=name of current class and
 * BASE=name of base class
 * At run time, use RBIsKindOf(CLASS, object) macro
 **************************************************************************************************************************
 * @file RBRTTI.h
 **************************************************************************************************************************/


#ifndef __RBRTTI_H__
#define __RBRTTI_H__


/**************************************************************************************************************************
 * Includes
 **************************************************************************************************************************/
#include "RBAllocations.h"
#include "RBString.h"

/**************************************************************************************************************************
 * Forward declarations
 **************************************************************************************************************************/

/**************************************************************************************************************************
 * Classes
 **************************************************************************************************************************/

class RBRTTI
{
public:
                            RBRTTI     (const RBString& strClassName, const RBRTTI* pClassParent);
    virtual                ~RBRTTI     ();

    bool                    IsRoot     () const;
    const RBRTTI*           GetParent  () const;
    const RBString&         GetName    () const;

    template<class T> bool  IsKindOf   () const;

private:
    const RBRTTI*           m_pParent;
    RBString                m_StrClassName;
};

#define RBDeclareRTTI(CLASS,BASE)                                           \
public:                                                                     \
    typedef BASE Super;                                                     \
    static const RBRTTI* GetStaticRTTI()                                    \
    {                                                                       \
            static const RBRTTI s_RTTI                                      \
            (                                                               \
                #CLASS,                                                     \
                BASE::GetStaticRTTI()                                       \
            );                                                              \
                                                                            \
            return &s_RTTI;                                                 \
    }                                                                       \
                                                                            \
    virtual const RBRTTI* GetRTTI() const                                   \
    {                                                                       \
        return GetStaticRTTI();                                             \
    }                                                                       \


#define RBDeclareRootRTTI(CLASS)                                            \
                                                                            \
public:                                                                     \
    static const RBRTTI* GetStaticRTTI()                                    \
    {                                                                       \
            static const RBRTTI s_RTTI                                      \
            (                                                               \
                #CLASS,                                                     \
                0                                                           \
            );                                                              \
                                                                            \
            return &s_RTTI;                                                 \
    }                                                                       \
                                                                            \
    virtual const RBRTTI* GetRTTI() const                                   \
    {                                                                       \
        return GetStaticRTTI();                                             \
    }                                                                       \
                                                                            \
    static bool IsKindOf(const RBRTTI* pClassRTTI, const CLASS* pObject)    \
    {                                                                       \
        if (pObject)                                                        \
        {                                                                   \
            return pObject->IsKindOf(pClassRTTI);                           \
        }                                                                   \
        return false;                                                       \
    }                                                                       \
                                                                            \
    bool IsKindOf(const RBRTTI* pClassRTTI) const                           \
    {                                                                       \
        const RBRTTI* pObjectRTTI = GetRTTI();                              \
        while (pObjectRTTI)                                                 \
        {                                                                   \
            if (pObjectRTTI == pClassRTTI)                                  \
            {                                                               \
                return true;                                                \
            }                                                               \
            else                                                            \
            {                                                               \
                pObjectRTTI = pObjectRTTI->GetParent();                     \
            }                                                               \
        }                                                                   \
        return false;                                                       \
    }                                                                       \

/**************************************************************************************************************************/

#define RbIsKindOf(CLASS, pObject) \
    CLASS::IsKindOf(CLASS::GetStaticRTTI(), pObject)

#define RBDynamicCast(CLASS, pObject) \
    (CLASS::IsKindOf(CLASS::GetStaticRTTI(), pObject) ? (CLASS*) pObject : (CLASS*)0)


#include "RBRTTI.inl"

#endif // __RBRTTI_H__
